<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      overflow-y: scroll;
      background-color: rgba(150, 150, 150, 0.5);
      font-size: 20px;
      font-weight: bold;
      line-height: 60px;
      width: 500px;
      margin: 0 auto;
      position: relative;
      text-align: center;
    }
    .list {
      position: absolute;
      top: 0;
      width: 100%;
    }
  </style>
  <body>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
 
    <div id="app">
      <div
        class="container"
        :style="{height:containerHeigth}"
        @scroll="handleScroll"
        ref="container"
      >
        <!-- 数据列表 -->
        <div class="list" :style="{top:listTop}">
          <!-- 列表项 -->
          <div
            v-for="item in showData"
            :key="item.id"
            :style="{height:size+'px'}"
          >
            {{item.content}}
          </div>
          <!-- 用于撑开高度的元素 -->
          <div class="bar" :style="{height:barHeigth}"></div>
        </div>
      </div>
    </div>
 
    <script>
      const { createApp, ref, computed } = Vue;
 
      createApp({
        setup() {
          //需要展示单条数据的高度
          let size = 60;
          //需要展示的起始下标
          let start = ref(0);
          // 需要展示数据的结束下标
          let end = ref(10);
          //每次渲染的节点个数
          let shownum = 10;
          //获取列表dom
          let container = ref(null);
 
          //需要渲染的数据
          let arrs = Array(1000)
            .fill("")
            .map((item, index) => ({
              id: index,
              content: `第${index + 1}条数据`,
            }));
          console.log(arrs);
          //需要展示出来的数据
          let showData = computed(() => {
            return arrs.slice(start.value, end.value);
          });
          //容器的高度
          let containerHeigth = computed(() => {
            return size * shownum + "px";
          });
          //撑开容器内容高度的元素高度
          let barHeigth = computed(() => {
            return size * arrs.length + "px";
          });
          //列表项上滚动该表top值
          let listTop = computed(() => {
            return start.value * size + "px";
          });
          //容器的滚动事件
          function handleScroll() {
            //获取容器顶部滚动条的尺寸
            const scrollTop = container.value.scrollTop;
            //计算卷曲的数据条数，用计算的结果作为获取数据的起始和结束下标
            //起始的下标就是卷去的数据条数，向下取整
            start.value = Math.floor(scrollTop / size);
            //结束下标就是起始下标加上需要展示的数据条数
            end.value = start.value + shownum;
          }
          return {
            size,
            container,
            showData,
            containerHeigth,
            barHeigth,
            listTop,
            handleScroll,
          };
        },
      }).mount("#app");
    </script>
  </body>
</html>